package scales.utils.collection.path
import scala.collection.IndexedSeqLike
import scales.utils.collection.Tree
import scales.utils.{PathFoldR, FoldR, LeftLike, deepestLast}
trait AbstractPathIterator[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]], T] extends Iterator[T] {
def initialPath : Path[Item, Section, CC]
var path = initialPath
val isForward = true
sealed trait State {
def hasNext : Boolean = true
def next : (State, T)
}
case object StartElem extends State {
def next = {
val ev = event
if (path.hasChildren) {
if (isForward)
path = path.firstChild.get
else {
path = deepestLast(path)
}
if (path.isItem)
(OnItem, ev)
else
(StartElem, ev)
} else
(EndElemS, ev)
}
}
final def canDoNext =
if (isForward)
path.hasNextSibling
else
path.hasPreviousSibling
case object OnItem extends State {
def next = {
val ev = event
if (canDoNext)
doNext(ev)
else {
path = path.top.right.get
(EndElemS, ev)
}
}
}
case object End extends State {
override def hasNext = false
def next = error("Can't go past the root")
}
def end : T
case object EndElemS extends State {
def next = {
val ev = end
if (canDoNext) {
doNext(ev)
} else {
if (path.top.isLeft) {
(End, ev)
} else {
path = path.top.right.get
(EndElemS, ev)
}
}
}
}
def doNext(ev : T) : (State, T) = {
path =
if (isForward)
path.nextSibling
else {
val t = path.previousSibling
if (t.isItem)
t
else
deepestLast(t)
}
if ( path.isItem )
(OnItem, ev)
else
(StartElem, ev)
}
def event : T
var nextState : State = initialPath.node.focus.fold(_ => OnItem, _ => StartElem)
def prepareNext {
}
def hasNext = nextState.hasNext
def next = {
val (ns, ev) = nextState.next
nextState = ns
prepareNext
ev
}
}
class DirectionIterator[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]]( val initialPath : Path[Item,Section,CC], override val isForward : Boolean = true ) extends AbstractPathIterator[Item, Section, CC, Path[Item,Section,CC]] {
def event = path
def end = path
override def prepareNext {
val donext =
(isForward && (nextState eq EndElemS)) ||
(!isForward && (nextState eq StartElem))
if (donext) {
next
}
}
}